package com.freedy.concurrent.immutable;


import lombok.extern.slf4j.Slf4j;

import java.sql.*;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * @author Freedy
 * @date 2021/4/24 17:19
 */
@Slf4j
public class PoolTest {

    public static void main(String[] args) throws Exception {
        long millis = System.currentTimeMillis();
        int size=10;
        int concurrentSize=1000;

        Pool pool = new Pool(size, "jdbc:mysql://192.168.169.2:3306/nacos?serverTimezone=UTC", "root", "Kz99596589");
        ArrayList<Thread> list = new ArrayList<>();
        for (int i = 0; i < concurrentSize; i++) {
            Thread thread = new Thread(() -> {
                Connection connection = null;
                try {
                    connection = pool.getConnection();
                    PreparedStatement statement = connection.prepareStatement("select * from users");
                    ResultSet resultSet = statement.executeQuery();
                    resultSet.next();
                    log.warn("查询出的账户{}-密码{}", resultSet.getString(1), resultSet.getString(2));
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                } finally {
                    pool.close(connection);
                }
            });
            list.add(thread);
        }
        list.forEach(Thread::start);
        list.forEach(i->{
            try {
                i.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        log.info("数据库连接池容量为{},总耗时{},并发量{}",size,System.currentTimeMillis()-millis,concurrentSize);
    }

}

@Slf4j
class Pool {
    private final int poolSize;
    private final Connection[] connections;
    private final AtomicIntegerArray connectStates;

    public Pool(int poolSize, String url, String username, String password) {
        this.poolSize = poolSize;
        this.connections = new Connection[poolSize];
        log.info("初始化数据库连接池........");
        for (int i = 0; i < poolSize; i++) {
            try {
                this.connections[i] = DriverManager.getConnection(url, username, password);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        this.connectStates = new AtomicIntegerArray(poolSize);
    }

    public Connection getConnection() {
        for (; ; ) {
            for (int i = 0; i < poolSize; i++) {
                if (connectStates.get(i) == 0) {
                    if (connectStates.compareAndSet(i, 0, 1)) {
                        log.info("获取{}连接", connections[i]);
                        return connections[i];
                    }
                }
            }
            synchronized (this) {
                try {
                    log.info("没有获取到连接,等待其他连接释放.....");
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void close(Connection connection) {
        if (connectStates != null) {
            for (int i = 0; i < poolSize; i++) {
                if (connections[i] == connection) {
                    //这里不会发生竞争
                    connectStates.set(i, 0);
                    log.info("归还{}连接", connection);
                    synchronized (this) {
                        this.notify();
                    }
                    break;
                }
            }
        }
    }


}

